package com.lnsoft.dqfs.server.util;

import com.sun.jna.Library;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Order(value = 2)
public class Libauth implements CommandLineRunner {
//public class Libauth {
    private static Logger logger = LoggerFactory.getLogger(Libauth.class);
    @Value("${licence.crtPath}")
    private String crtPath;

    @Value("${licence.keyPath}")
    private String keyPath;

    public Libauth() {
    }

    //  实现CommandLineRunner接口的方法，使springboot扫描完成之后，执行该接口方法：验证部署授权。
    @Override
    public void run(String... args) throws Exception {
//        verifyAuthorization();
    }

    public void verifyAuthorization() {
        //实例化动态库
        Object obj = CLibrary1.INSTANCE;
        Object obj1 = CLibrary2.INSTANCE;
        boolean flagVerify = false;
        //获取激活码
        Pointer pszActCode = new Memory(1024);
        IntByReference pdwActCodeLen = new IntByReference();
        pdwActCodeLen.setValue(0);
        boolean flagGetActCode = CLibrary.INSTANCE.GetActCode(pszActCode, pdwActCodeLen);
        byte[] bytes = pszActCode.getByteArray(0, pdwActCodeLen.getValue());
        String str = new String(bytes);
        logger.info("获取激活码返回值: " + flagGetActCode + " " + str + " " + pdwActCodeLen.getValue());

        //获取系统代码部署的路径
        String filePath = System.getProperty("catalina.home");
        if (filePath == null) {
            logger.warn("证书文件路径无法找到！！");
//			filePath="/weblogic";
            System.exit(0);
        }
        //解密授权证书
        Pointer pszLiceseCrt = new Memory(1024);
        String filePathCrt = filePath + crtPath;
        pszLiceseCrt.setString(0, filePathCrt);

        Pointer pszLicenseKey = new Memory(1024);
        String filePathKey = filePath + keyPath;
        pszLicenseKey.setString(0, filePathKey);

        Pointer pszDecCrt = new Memory(1024);
        IntByReference pdwLen = new IntByReference();
        pdwLen.setValue(0);
        int returnValue = CLibrary.INSTANCE.DecryptCrt(pszLiceseCrt, pszLicenseKey, pszDecCrt, pdwLen);
        byte[] bytes1 = pszDecCrt.getByteArray(0, pdwLen.getValue());
        String str1 = new String(bytes1);
        logger.info("解密证书返回值: " + returnValue + " " + str1 + " " + pdwLen.getValue());
        //校验授权
        if (flagGetActCode && returnValue == 0) {
            flagVerify = CLibrary.INSTANCE.VerifyAuth(pszActCode, pdwActCodeLen.getValue(), pszDecCrt, pdwLen.getValue());
        }
        if (flagVerify) {
            logger.info("业务系统与CPU和硬盘序列号绑定授权校验成功");
        } else {
            logger.info("业务系统与CPU和硬盘序列号绑定授权校验失败");
            //授权失败，停止服务启动
            System.exit(0);
            boolean flagTemp = true;
            while (flagTemp) {
            }
        }
    }

    /**
     * 使用JNA调用so动态库
     * libauth.so动态库实现功能：业务系统与CPU和硬盘序列号进行绑定，防止没有授权的程序软件包部署在设备上。
     * libauth.so会调用libssl.so、libcrypto.so系统动态库
     */
    interface CLibrary extends Library {
        CLibrary INSTANCE = (CLibrary) Native.loadLibrary("auth", CLibrary.class);

        /**
         * 函 数 名：GetActCode
         * 功    能：获取激活码
         * 注    意：pszActCode所指向预留空间不小于64字节。
         * 算法实现：
         * 全局变量：
         * 参    数：pszActCode   : [OUT] 返回获取设备激活码缓存地址
         * pdwActCodeLen: [OUT] 返回获取设备激活码长度
         * 返 回 值：成功返回TRUE, 失败返回FALSE.
         */
        boolean GetActCode(Pointer pszActCode, IntByReference pdwActCodeLen);

        /**
         * 函 数 名：DecryptCrt
         * 功    能：解密授权证书
         * 注    意：pszDecCrt所指向预留空间不小于64字节。
         * 算法实现：
         * 全局变量：
         * 参    数：pszLiceseCrt   : [IN] 输入授权证书路径缓存地址
         * pszLicenseKey  : [IN] 输入公钥路径缓存地址
         * pszDecCrt      : [OUT] 返回解密授权证书后得到激活码的缓存地址
         * pdwLen         : [OUT] 返回解密后得到激活码的激活码长度
         * 返 回 值：成功返回 0, 失败返回非 0 错误码.-1:入参非法; -2:文件路径错误(打开文件失败); -3:读取文件错误; -4:授权过期
         */
        int DecryptCrt(Pointer pszLiceseCrt, Pointer pszLicenseKey, Pointer pszDecCrt, IntByReference pdwLen);

        /**
         * 函 数 名：VerifyAuth
         * 功    能：校验授权
         * 注    意：
         * 算法实现：
         * 全局变量：
         * 参    数：pszActCode   : [IN] 输入设备激活码缓存地址
         * dwActCodeLen : [IN] 输入设备激活码长度
         * pszDecCrt    : [IN] 输入解密授权证书后得到激活码的缓存地址
         * dwDecCrtLen  : [IN] 输入解密后得到激活码的激活码长度
         * 返 回 值：成功返回TRUE, 失败返回FALSE.
         */
        boolean VerifyAuth(Pointer pszActCode, int dwActCodeLen, Pointer pszDecCrt, int dwDecCrtLen);
    }

    interface CLibrary1 extends Library {
        CLibrary1 INSTANCE = (CLibrary1) Native.loadLibrary("ssl", CLibrary1.class);
    }

    interface CLibrary2 extends Library {
        CLibrary2 INSTANCE = (CLibrary2) Native.loadLibrary("crypto", CLibrary2.class);
    }
}
